package ice.server.comm;

import org.hibernate.transform.Transformers;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.util.CollectionUtils;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CommRepositoryImpl {

    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
    /**
     * 自定义JPQL语句执行列表查询的方法，以map的格式返回结果集
     * @author zhangrb
     * @user all
     * @date 2019-08-20
     * @param jpql 语句
     * @param paramters 语句中的参数值列表，按照参数顺序对应
     * @return jpsql语句的查询结果
     */
    protected List<Map<String, Object>> searchByJPQL(String jpql, List<Object> paramters) {
        Query q = makeQuery(jpql, paramters);
        q.unwrap(org.hibernate.query.Query.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List<Map<String, Object>> l = q.getResultList();
        return l;
    }

    /**
     * 自定义JPQL语句执行列表查询的方法，以s自定义对象的的格式返回结果集
     * @author zhangrb
     * @user all
     * @date 2019-08-20
     * @param jpql 语句
     * @param paramters 语句中的参数值列表，按照参数顺序对应
     * @return jpsql语句的查询结果
     */
    protected <G> List<G> searchByJPQL(String jpql, List<Object> paramters, Class<G> c) {
        Query q = makeQuery(jpql, paramters);
        q.unwrap(org.hibernate.query.Query.class).setResultTransformer(Transformers.aliasToBean(c));
        List<G> l = q.getResultList();
        return l;
    }

    /**
     * 自定义JPQL语句执行列表查询的方法，以map的格式返回结果集
     * @author zhangrb
     * @user all
     * @date 2019-08-20
     * @param jpql 语句
     * @param paramters 语句中的参数值列表，按照参数顺序对应
     * @return jpsql语句的查询结果
     */
    protected Page<Map<String, Object>> searchByJPQL(String jpql, List<Object> paramters, Pageable pageable) {
        Query q = makeQuery(jpql, paramters);
        q.setFirstResult((int)pageable.getOffset());
        q.setMaxResults(pageable.getPageSize());
        q.unwrap(org.hibernate.query.Query.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List<Map<String, Object>> l = q.getResultList();
        int total = getTotal(jpql, paramters);
        return new PageImpl(l, pageable, total);
    }

    /**
     * 自定义JPQL语句执行列表查询的方法，以s自定义对象的的格式返回结果集
     * @author zhangrb
     * @user all
     * @date 2019-08-20
     * @param jpql 语句
     * @param paramters 语句中的参数值列表，按照参数顺序对应
     * @return jpsql语句的查询结果
     */
    protected <G> Page<G> searchByJPQL(String jpql, List<Object> paramters, Class<G> c, Pageable pageable) {
        Query q = makeQuery(jpql, paramters);
        q.setFirstResult((int)pageable.getOffset());
        q.setMaxResults(pageable.getPageSize());
        q.unwrap(org.hibernate.query.Query.class).setResultTransformer(Transformers.aliasToBean(c));
        List<G> l = q.getResultList();
        int total = getTotal(jpql, paramters);
        return new PageImpl(l, pageable, total);
    }

    private int getTotal(String jpql, List<Object> paramters) {
        // 将jpql中的结果字段改为count(*),并不会慢，数据库会做优化处理
        Pattern test = Pattern.compile("(select)(.*?)(from)",Pattern.CASE_INSENSITIVE);
        Matcher m = test.matcher(jpql);
        String countJpql = m.replaceFirst("$1 count(*) $3");
        Query cntq = makeQuery(countJpql, paramters);
        int total = ((Long)cntq.getSingleResult()).intValue();
        return total;
    }

    /**
     * 组织jpql查询对象
     * @author zhangrb
     * @user zhangrb
     * @date 2019-08-20
     * @param jpql 语句
     * @param paramters 语句中的参数值列表，按照参数顺序对应
     * @return 查询对象
     */
    private Query makeQuery(String jpql, List<Object> paramters) {
        Query q = entityManager.createQuery(jpql);
        if(!CollectionUtils.isEmpty(paramters)) {
            for(int i = 0; i < paramters.size(); i++) {
                q.setParameter(i + 1, paramters.get(i));
            }
        }
        return q;
    }

    public List<Map<String, Object>> searchByJPQLModel(JPSQLModel jm) {
        JPQLParseResult jr = getJPQLParseResult(jm);
        return searchByJPQL(jr.getJpql(), jr.getParamList());
    }

    public Page<Map<String, Object>> searchByJPQLModel(JPSQLModel jm, Pageable p) {
        JPQLParseResult jr = getJPQLParseResult(jm);
        return searchByJPQL(jr.getJpql(), jr.getParamList(), p);
    }

    public <G> List<G> searchByJPQLModel(JPSQLModel jm, Class<G> c) {
        JPQLParseResult jr = getJPQLParseResult(jm);
        return searchByJPQL(jr.getJpql(), jr.getParamList(), c);
    }

    public <G> Page<G> searchByJPQLModel(JPSQLModel jm, Pageable p, Class<G> c) {
        JPQLParseResult jr = getJPQLParseResult(jm);
        return searchByJPQL(jr.getJpql(), jr.getParamList(), c, p);
    }

    private JPQLParseResult getJPQLParseResult(JPSQLModel jm) {
        JPQLParseResult jr = JPSQLModelParser.parseToJPQL(jm);
        if(jr == null) {
            throw new JPQLModelException("JPSQLModel解析失败");
        }
        return jr;
    }
}
